package lexer

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

// Lexer 结构体表示词法分析器
type Lexer struct {
	input        string
	position     int  // 当前位置（指向当前字符）
	readPosition int  // 当前读取位置（指向下一个字符）
	ch           rune // 当前正在查看的字符
	line         int  // 当前行号
	column       int  // 当前列号
	width        int  // 当前字符的宽度（以字节为单位）
}

// New 创建一个新的词法分析器
func New(input string) *Lexer {
	l := &Lexer{
		input:  input,
		line:   1, // 行号从1开始
		column: 0, // 列号从0开始
	}
	l.readChar() // 初始化第一个字符
	return l
}

// readChar 读取下一个Unicode字符并前进
func (l *Lexer) readChar() {
	if l.readPosition >= len(l.input) {
		l.ch = 0 // 'NUL' 表示结束
		l.width = 0
	} else {
		var size int
		l.ch, size = utf8.DecodeRuneInString(l.input[l.readPosition:])
		l.width = size
	}
	l.position = l.readPosition
	l.readPosition += l.width

	// 更新列号和行号
	l.column++
	if l.ch == '\n' {
		l.line++
		l.column = 0
	}
}

// peekChar 查看下一个Unicode字符但不前进
func (l *Lexer) peekChar() rune {
	if l.readPosition >= len(l.input) {
		return 0
	}
	r, _ := utf8.DecodeRuneInString(l.input[l.readPosition:])
	return r
}

// NextToken 获取下一个token
func (l *Lexer) NextToken() Token {
	var tok Token

	l.skipWhitespace()

	startLine := l.line
	startColumn := l.column

	switch l.ch {
	case '=':
		if l.peekChar() == '=' {
			ch := l.ch
			l.readChar()
			tok = Token{
				Type:    EQ,
				Literal: string(ch) + string(l.ch),
				Line:    startLine,
				Column:  startColumn,
			}
		} else if l.peekChar() == '>' {
			l.readChar()
			tok = Token{Type: ARROW, Literal: "=>", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(ASSIGN, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '+':
		if l.peekChar() == '+' {
			l.readChar()
			tok = Token{Type: INCREMENT, Literal: "++", Line: startLine, Column: startColumn}
		} else if l.peekChar() == '=' {
			l.readChar()
			tok = Token{Type: PLUS_ASSIGN, Literal: "+=", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(PLUS, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '-':
		if l.peekChar() == '-' {
			l.readChar()
			tok = Token{Type: DECREMENT, Literal: "--", Line: startLine, Column: startColumn}
		} else if l.peekChar() == '=' {
			l.readChar()
			tok = Token{Type: MINUS_ASSIGN, Literal: "-=", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(MINUS, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '!':
		if l.peekChar() == '=' {
			ch := l.ch
			l.readChar()
			literal := string(ch) + string(l.ch)
			tok = Token{Type: NOT_EQ, Literal: literal, Line: startLine, Column: startColumn}
		} else {
			tok = newToken(BANG, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '*':
		if l.peekChar() == '=' {
			l.readChar()
			tok = Token{Type: MUL_ASSIGN, Literal: "*=", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(ASTERISK, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '/':
		// 处理注释
		if l.peekChar() == '/' {
			l.skipLineComment()
			return l.NextToken()
		} else if l.peekChar() == '*' {
			l.skipBlockComment()
			return l.NextToken()
		} else if l.peekChar() == '=' {
			l.readChar()
			tok = Token{Type: DIV_ASSIGN, Literal: "/=", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(SLASH, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '%':
		if l.peekChar() == '=' {
			l.readChar()
			tok = Token{Type: MOD_ASSIGN, Literal: "%=", Line: startLine, Column: startColumn}
		} else {
			tok = newToken(PERCENT, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '<':
		if l.peekChar() == '=' {
			ch := l.ch
			l.readChar()
			literal := string(ch) + string(l.ch)
			tok = Token{Type: LTE, Literal: literal, Line: startLine, Column: startColumn}
		} else {
			tok = newToken(LT, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '>':
		if l.peekChar() == '=' {
			ch := l.ch
			l.readChar()
			literal := string(ch) + string(l.ch)
			tok = Token{Type: GTE, Literal: literal, Line: startLine, Column: startColumn}
		} else {
			tok = newToken(GT, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '&':
		if l.peekChar() == '&' {
			ch := l.ch
			l.readChar()
			literal := string(ch) + string(l.ch)
			tok = Token{Type: AND, Literal: literal, Line: startLine, Column: startColumn}
		} else {
			tok = newToken(ILLEGAL, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case '|':
		if l.peekChar() == '|' {
			ch := l.ch
			l.readChar()
			literal := string(ch) + string(l.ch)
			tok = Token{Type: OR, Literal: literal, Line: startLine, Column: startColumn}
		} else {
			tok = newToken(ILLEGAL, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
		}
	case ';':
		tok = newToken(SEMICOLON, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case ':':
		tok = newToken(COLON, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '?':
		tok = newToken(QUESTION, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case ',':
		tok = newToken(COMMA, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '.':
		tok = newToken(DOT, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '(':
		tok = newToken(LPAREN, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case ')':
		tok = newToken(RPAREN, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '{':
		tok = newToken(LBRACE, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '}':
		tok = newToken(RBRACE, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '[':
		tok = newToken(LBRACKET, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case ']':
		tok = newToken(RBRACKET, l.ch)
		tok.Line = startLine
		tok.Column = startColumn
	case '"':
		tok.Type = STRING
		tok.Literal = l.readString()
		// 检测未闭合的字符串
		if tok.Literal == "" && l.ch == 0 {
			fmt.Println("检测到未闭合的字符串")
			tok.Type = ILLEGAL
			tok.Literal = "未闭合的字符串"
		}
		tok.Line = startLine
		tok.Column = startColumn
	case '\'':
		tok.Type = STRING
		tok.Literal = l.readSingleQuoteString()
		// 检测未闭合的字符串
		if tok.Literal == "" && l.ch == 0 {
			fmt.Println("检测到未闭合的单引号字符串")
			tok.Type = ILLEGAL
			tok.Literal = "未闭合的字符串"
		}
		tok.Line = startLine
		tok.Column = startColumn
	case '`':
		tok.Type = TEMPLATE
		tok.Literal = l.readBacktickString()
		if tok.Literal == "" && l.ch == 0 {
			tok.Type = ILLEGAL
			tok.Literal = "未闭合的模板字符串"
		}
		tok.Line = startLine
		tok.Column = startColumn
	case 0:
		tok.Literal = ""
		tok.Type = EOF
		tok.Line = startLine
		tok.Column = startColumn
	default:
		if isLetter(l.ch) {
			tok.Literal = l.readIdentifier()
			tok.Type = LookupIdent(tok.Literal)
			tok.Line = startLine
			tok.Column = startColumn
			return tok
		} else if isDigit(l.ch) {
			numToken := l.readNumber()
			numToken.Line = startLine
			numToken.Column = startColumn
			return numToken
		} else {
			tok = newToken(ILLEGAL, l.ch)
			tok.Line = startLine
			tok.Column = startColumn
			if l.ch == '$' && l.peekChar() == '$' {
				l.readChar()
				tok.Literal = "$$"
			}
		}
	}

	l.readChar()
	return tok
}

// skipWhitespace 跳过空白字符
func (l *Lexer) skipWhitespace() {
	for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' {
		l.readChar()
	}
}

// skipLineComment 跳过行注释
func (l *Lexer) skipLineComment() {
	// 跳过 //
	l.readChar()
	l.readChar()

	// 跳过直到行尾或文件结束
	for l.ch != '\n' && l.ch != 0 {
		l.readChar()
	}
}

// skipBlockComment 跳过块注释
func (l *Lexer) skipBlockComment() {
	// 跳过 /*
	l.readChar()
	l.readChar()

	// 跳过直到 */ 或文件结束
	for !(l.ch == '*' && l.peekChar() == '/') && l.ch != 0 {
		l.readChar()
	}

	if l.ch != 0 {
		// 跳过 */
		l.readChar()
		l.readChar()
	}
}

// readIdentifier 读取标识符
func (l *Lexer) readIdentifier() string {
	position := l.position
	for isLetter(l.ch) || isDigit(l.ch) {
		l.readChar()
	}
	return l.input[position:l.position]
}

// readNumber 读取数字
func (l *Lexer) readNumber() Token {
	position := l.position
	isFloat := false

	for isDigit(l.ch) {
		l.readChar()

		// 检查是否是浮点数（包含小数点）
		if l.ch == '.' && isDigit(l.peekChar()) {
			isFloat = true
			l.readChar() // 读取小数点

			// 读取小数点后的数字
			for isDigit(l.ch) {
				l.readChar()
			}
		}
	}

	// 检查科学计数法 (e.g., 1e10, 1.5e-5)
	if (l.ch == 'e' || l.ch == 'E') && (isDigit(l.peekChar()) ||
		((l.peekChar() == '+' || l.peekChar() == '-') && l.readPosition+l.width+1 < len(l.input) &&
			isDigit(peekNextRune(l)))) {
		isFloat = true
		l.readChar() // 读取 'e' 或 'E'

		// 处理可选的 '+' 或 '-'
		if l.ch == '+' || l.ch == '-' {
			l.readChar()
		}

		// 读取指数部分
		for isDigit(l.ch) {
			l.readChar()
		}
	}

	if isFloat {
		return Token{Type: FLOAT, Literal: l.input[position:l.position], Line: l.line, Column: l.column}
	}

	return Token{Type: INT, Literal: l.input[position:l.position], Line: l.line, Column: l.column}
}

// readString 读取双引号字符串
func (l *Lexer) readString() string {
	position := l.position + l.width // 跳过开始的双引号
	isUnclosed := true

	for {
		l.readChar()
		// 如果遇到未转义的双引号或EOF，结束
		if l.ch == '"' {
			isUnclosed = false
			break
		}
		if l.ch == 0 { // EOF
			break
		}
		// 处理转义字符
		if l.ch == '\\' {
			l.readChar() // 读取转义字符后的字符
		}
	}

	// 如果字符串未闭合，则返回空字符串作为标记
	if isUnclosed {
		return ""
	}

	return l.input[position:l.position]
}

// readSingleQuoteString 读取单引号字符串
func (l *Lexer) readSingleQuoteString() string {
	position := l.position + l.width // 跳过开始的单引号
	isUnclosed := true

	for {
		l.readChar()
		// 如果遇到未转义的单引号或EOF，结束
		if l.ch == '\'' {
			isUnclosed = false
			break
		}
		if l.ch == 0 { // EOF
			break
		}
		// 处理转义字符
		if l.ch == '\\' {
			l.readChar() // 读取转义字符后的字符
		}
	}

	// 如果字符串未闭合，则返回空字符串作为标记
	if isUnclosed {
		return ""
	}

	return l.input[position:l.position]
}

// readTemplateString 读取模板字符串的文本部分，直到${ 或结束的反引号
func (l *Lexer) readTemplateString() (string, bool, bool) {
	position := l.position + l.width // 跳过开始的反引号或 }
	isUnclosed := true
	hasInterpolation := false

	for {
		l.readChar()
		if l.ch == '`' { // 字符串结束
			isUnclosed = false
			break
		}
		if l.ch == 0 { // EOF
			break
		}
		// 检测字符串插值 ${
		if l.ch == '$' && l.peekChar() == '{' {
			hasInterpolation = true
			l.readChar() // 读取 {
			break
		}
		// 处理转义字符
		if l.ch == '\\' {
			l.readChar() // 读取转义字符后的字符
		}
	}

	// 如果字符串未闭合，则返回空字符串作为标记
	if isUnclosed && l.ch == 0 {
		return "", true, false
	}

	return l.input[position:l.position], isUnclosed, hasInterpolation
}

// readBacktickString 读取反引号字符串
func (l *Lexer) readBacktickString() string {
	position := l.position + l.width // 跳过开始的反引号
	isUnclosed := true

	for {
		l.readChar()
		// 如果遇到未转义的反引号或EOF，结束
		if l.ch == '`' {
			isUnclosed = false
			break
		}
		if l.ch == 0 { // EOF
			break
		}
		// 处理转义字符
		if l.ch == '\\' {
			l.readChar() // 读取转义字符后的字符
		}
		// 注意：我们不跳过换行符，因为模板字符串支持多行文本
	}

	// 如果字符串未闭合，则返回空字符串作为标记
	if isUnclosed {
		return ""
	}

	return l.input[position:l.position]
}

// isLetter 检查一个rune是否是字母、下划线或Unicode字符（允许中文标识符）
func isLetter(ch rune) bool {
	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf
}

// isDigit 检查一个rune是否是数字
func isDigit(ch rune) bool {
	return '0' <= ch && ch <= '9'
}

// newToken 创建一个新的Token
func newToken(tokenType TokenType, ch rune) Token {
	return Token{Type: tokenType, Literal: string(ch)}
}

// GetPosition 获取当前词法分析器的位置状态
func (l *Lexer) GetPosition() (position int, readPosition int, ch rune) {
	return l.position, l.readPosition, l.ch
}

// SetPosition 设置词法分析器的位置状态
func (l *Lexer) SetPosition(position int, readPosition int, ch rune) {
	l.position = position
	l.readPosition = readPosition
	l.ch = ch
}

// GetSource 返回词法分析器的完整源代码
func (l *Lexer) GetSource() string {
	return l.input
}

// peekNextRune 获取peekChar的下一个字符
func peekNextRune(l *Lexer) rune {
	pos := l.readPosition + utf8.RuneLen(l.peekChar())
	if pos >= len(l.input) {
		return 0
	}
	r, _ := utf8.DecodeRuneInString(l.input[pos:])
	return r
}

// GetSourceLine 获取源代码中指定行的内容
func (l *Lexer) GetSourceLine(lineNumber int) string {
	lines := strings.Split(l.input, "\n")
	if lineNumber > 0 && lineNumber <= len(lines) {
		return lines[lineNumber-1]
	}
	return ""
}
